using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;
using Making.Avalonia.WebView.Core.Abstractions;
using Making.Avalonia.WebView.Core.Models;
using Making.Avalonia.WebView.Core.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Making.Avalonia.WebView.Core;

public class MakingWebView : NativeControlHost
{
    private readonly IWebViewProvider _webViewProvider;
    private IPlatformHandle? _nativeWebView;
    private WebViewConfiguration _configuration = new();

    public static readonly DirectProperty<MakingWebView, double> ZoomFactorProperty =
        AvaloniaProperty.RegisterDirect<MakingWebView, double>(
            nameof(ZoomFactor),
            x => x.ZoomFactor,
            (x, y) => x.ZoomFactor = y);

    public static readonly DirectProperty<MakingWebView, Uri?> SourceProperty =
        AvaloniaProperty.RegisterDirect<MakingWebView, Uri?>(
            nameof(Source),
            x => x.Source,
            (x, y) => x.Source = y);

    public static readonly DirectProperty<MakingWebView, string?> UserDataFolderProperty =
        AvaloniaProperty.RegisterDirect<MakingWebView, string?>(
            nameof(UserDataFolder),
            x => x.UserDataFolder,
            (x, y) => x.UserDataFolder = y);

    public static readonly DirectProperty<MakingWebView, string?> HostPageProperty =
        AvaloniaProperty.RegisterDirect<MakingWebView, string?>(
            nameof(HostPage),
            x => x.HostPage,
            (x, y) => x.HostPage = y);

    public static readonly DirectProperty<MakingWebView, IServiceProvider?> ServiceProviderProperty =
        AvaloniaProperty.RegisterDirect<MakingWebView, IServiceProvider?>(
            nameof(ServiceProvider),
            x => x.ServiceProvider,
            (x, y) => x.ServiceProvider = y);

    public double ZoomFactor
    {
        get => _nativeWebView != null ? _webViewProvider.GetZoomFactor(_nativeWebView) : _configuration.InitialZoomFactor;
        set
        {
            if (Math.Abs(_configuration.InitialZoomFactor - value) > 0.001)
            {
                _configuration.InitialZoomFactor = value;
                if (_nativeWebView != null)
                {
                    _webViewProvider.SetZoomFactor(_nativeWebView, value);
                }
            }
        }
    }

    public Uri? Source
    {
        get => _configuration.InitialSource;
        set
        {
            if (_configuration.InitialSource != value)
            {
                _configuration.InitialSource = value;
                if (_nativeWebView != null && value != null)
                {
                    _ = _webViewProvider.NavigateAsync(_nativeWebView, value);
                }
            }
        }
    }

    public string? UserDataFolder
    {
        get => _configuration.UserDataFolder;
        set => _configuration.UserDataFolder = value;
    }

    public string? HostPage
    {
        get => _configuration.HostPage;
        set => _configuration.HostPage = value;
    }

    public IServiceProvider? ServiceProvider
    {
        get => _configuration.ServiceProvider;
        set => _configuration.ServiceProvider = value;
    }

    public event EventHandler<WebResourceRequestedEventArgs>? WebResourceRequested
    {
        add => _webViewProvider.WebResourceRequested += value;
        remove => _webViewProvider.WebResourceRequested -= value;
    }

    public event EventHandler<NavigationEventArgs>? NavigationStarting
    {
        add => _webViewProvider.NavigationStarting += value;
        remove => _webViewProvider.NavigationStarting -= value;
    }

    public event EventHandler<NavigationEventArgs>? NavigationCompleted
    {
        add => _webViewProvider.NavigationCompleted += value;
        remove => _webViewProvider.NavigationCompleted -= value;
    }

    public MakingWebView() : this(null)
    {
    }

    public MakingWebView(IServiceProvider? serviceProvider)
    {
        _configuration.ServiceProvider = serviceProvider ?? CreateDefaultServiceProvider();
        _webViewProvider = WebViewProviderFactory.CreateProvider(_configuration.ServiceProvider);
    }

    protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent)
    {
        if (!Design.IsDesignMode)
        {
            _nativeWebView = _webViewProvider.CreateWebView(parent, _configuration);
            return _nativeWebView;
        }

        return base.CreateNativeControlCore(parent);
    }

    protected override void DestroyNativeControlCore(IPlatformHandle control)
    {
        if (_nativeWebView != null)
        {
            _webViewProvider.DestroyWebView(_nativeWebView);
            _nativeWebView = null;
        }
        else
        {
            base.DestroyNativeControlCore(control);
        }
    }

    public void Navigate(string uri) => Source = new Uri(uri);
    public void Navigate(Uri uri) => Source = uri;

    public async Task<string> ExecuteScriptAsync(string script)
    {
        if (_nativeWebView != null)
            return await _webViewProvider.ExecuteScriptAsync(_nativeWebView, script);
        return string.Empty;
    }

    public void GoBack()
    {
        if (_nativeWebView != null && _webViewProvider.CanGoBack(_nativeWebView))
            _webViewProvider.GoBack(_nativeWebView);
    }

    public void GoForward()
    {
        if (_nativeWebView != null && _webViewProvider.CanGoForward(_nativeWebView))
            _webViewProvider.GoForward(_nativeWebView);
    }

    public void Reload()
    {
        if (_nativeWebView != null)
            _webViewProvider.Reload(_nativeWebView);
    }

    public void AddWebResourceRequestedFilter(string filter)
    {
        if (_nativeWebView != null)
            _webViewProvider.AddWebResourceFilter(_nativeWebView, filter);
    }

    private static IServiceProvider CreateDefaultServiceProvider()
    {
        var services = new ServiceCollection();
        services.AddLogging();
        return services.BuildServiceProvider();
    }
}